//
//  JwJailBreak.m
//  JwPack
//
//  Created by 陈警卫 on 2022/8/19.
//

#import "JwJailBreak.h"
#import <dlfcn.h>
#import <sys/stat.h>
#import <string.h>
#import <stdlib.h>
#import <mach-o/dyld.h>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

@implementation JwJailBreak

#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
#define USER_APP_PATH @"/User/Applications/"
#define CYDIA_APP_PATH @"/Applications/Cydia.app"

const char * jailbreak_tool_pathes[] = {
    "/Applications/Cydia.app",
    "/Library/MobileSubstrate/MobileSubstrate.dylib",
    "/bin/bash",
    "/usr/sbin/sshd",
    "/etc/apt"
};

- (void)jw_checkJailBreakWithSuccess:(void (^)(void))success {
    @autoreleasepool {
        if (!success) return;
        
        // 检查路径是否存在
        for (int i = 0; i < ARRAY_SIZE(jailbreak_tool_pathes); i++) {
            NSString *path = [NSString stringWithUTF8String:jailbreak_tool_pathes[i]];
            if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
                success();
                return;
            }
        }
        
        // 检查是否能打开Cydia的URL Scheme
        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"cydia://package/com.example.package"]]) {
            success();
            return;
        }
        
        // 检查用户应用路径是否存在
        if ([[NSFileManager defaultManager] fileExistsAtPath:USER_APP_PATH]) {
            success();
            return;
        }
        
        // 检查环境变量
        char *env = getenv("DYLD_INSERT_LIBRARIES");
        if (env != NULL) {
            success();
            return;
        }
        
        // 检查特定路径是否存在
        struct stat stat_info;
        NSArray *pathsToCheck = @[
            CYDIA_APP_PATH,
            @"/Library/MobileSubstrate/MobileSubstrate.dylib",
            @"/var/lib/cydia/",
            @"/var/cache/apt"
        ];
        for (NSString *path in pathsToCheck) {
            if (0 == stat([path UTF8String], &stat_info)) {
                success();
                return;
            }
        }
        
        // 检查`stat`函数的动态库来源
        int ret;
        Dl_info dylib_info;
        int (*func_stat)(const char *,struct stat *) = stat;
        if ((ret = dladdr(func_stat, &dylib_info))) {
            if (strcmp(dylib_info.dli_fname, "/usr/lib/system/libsystem_kernel.dylib")) {
                success();
                return;
            }
        }
    }
}

@end
